#include "s_ccs811.h"

#include <stdio.h>
#include <string.h>

static unsigned char s_ccs811_swreset_data[4] = {0x11, 0xE5, 0x72, 0x8A};

char s_ccs811_out_data[50];
signed short s_ccs811_out_data_len = 30;

s_ccs811_data_t ccs811_t;
////////////////////////////////////////////////////////////////////////////////
#include "h_cc2640r2f_iics.h"

#include "h_cc2640r2f_define.h"

#include <ti/drivers/PIN.h>
#include <ti/devices/cc26x0r2/driverlib/ioc.h>

#define S_CCS811_DEBUG					H_CC2640R2F_UART_Debug



static const PIN_Config ccs811_gpio_outputcfg[] =
{
     S_CCS811_nWake_PIN | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MAX,
     S_CCS811_nReset_PIN | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MAX,

    PIN_TERMINATE
};
static PIN_Handle ccs811_gpio_outputhandle = NULL;
static PIN_State ccs811_gpio_outputstate;

//extern I2C_HandleTypeDef hi2c1;

static signed char s_ccs811_iic_readbuff(unsigned char reg, \
											unsigned char *data, \
												unsigned short len)
{
	signed char rslt = 0;
	
	rslt = H_CC2640R2F_IICS0_ReadBuff_Slow(S_CCS811_ADDR, reg, data, len);
	
	return rslt;
}


static signed char s_ccs811_iic_writebuff(unsigned char reg, \
											unsigned char *data, \
												unsigned short len)
{
	signed char rslt = 0;
	
	rslt = H_CC2640R2F_IICS0_WriteBuff_Slow(S_CCS811_ADDR, reg, data, len);
	
	return rslt;
}

static signed char s_ccs811_gpio_outputinit(void)
{
    if(NULL != ccs811_gpio_outputhandle)
    {
        return 0;
    }
    ccs811_gpio_outputhandle = PIN_open(&ccs811_gpio_outputstate, \
                                        ccs811_gpio_outputcfg);
    return 0;
}

static void s_ccs811_nWake_enable(void)
{
    PIN_setOutputValue(ccs811_gpio_outputhandle, S_CCS811_nWake_PIN, 0);
}

static void s_ccs811_nWake_disable(void)
{
    PIN_setOutputValue(ccs811_gpio_outputhandle, S_CCS811_nWake_PIN, 1);
}

static void s_ccs811_nReset_enable(void)
{
    PIN_setOutputValue(ccs811_gpio_outputhandle, S_CCS811_nReset_PIN, 0);
}

static void s_ccs811_nReset_disable(void)
{
    PIN_setOutputValue(ccs811_gpio_outputhandle, S_CCS811_nReset_PIN, 1);
}

static void s_ccs811_delay_us(unsigned int dly)
{
    unsigned char i = 0;
    for(i = 0U; i < 12U; i ++)
    {
        CPUdelay(dly);
    }

}
////////////////////////////////////////////////////////////////////////////////

static void s_ccs811_delay_ms(unsigned int dly)
{
    unsigned short i = 0U;
    for(i = 0U; i < 1000; i++)
    {
        s_ccs811_delay_us(dly);
    }
}

static unsigned char s_ccs811_readstatus(void)
{
	unsigned char status;
	s_ccs811_iic_readbuff(S_CCS811_STATUS, &status, 1);
	return status;
}

static signed char s_ccs811_firmware_start(void)
{
	//signed char rslt;
//	unsigned char data = 0xFF;
	return s_ccs811_iic_writebuff(S_CCS811_APP_START, NULL, 0);
}

static signed char s_ccs811_meas_mode_set(void)
{
	unsigned char data = S_CCS811_MEAS_MODE_DEFAULT;
	return s_ccs811_iic_writebuff(S_CCS811_MEAS_MODE, &data, 1);
}

static signed char s_ccs811_meas_mode_get(unsigned char *data)
{
//    unsigned char data = 0x10;
    return s_ccs811_iic_readbuff(S_CCS811_MEAS_MODE, data, 1);
}

static signed char s_ccs811_meas_mode_check(void)
{
    unsigned char meas_mode = 0U;
    if(s_ccs811_meas_mode_get(&meas_mode))
    {
        S_CCS811_DEBUG("Get measure mode failed\r\n");
        return (-1);
    }
    else
    {
        S_CCS811_DEBUG("The measure mode is 0x%02x\r\n", meas_mode);
        if(S_CCS811_MEAS_MODE_DEFAULT == meas_mode)
        {
            return 0;
        }
        else
        {
            return (-2);
        }
    }
}

// signed char S_CCS811_GetNewData(s_ccs811_data_t * ccs811_t)
// {
// //    unsigned char data[S_CCS811_ALG_RESULT_DATA_LEN];
// //    signed char rslt = 0;
// //
// //    rslt = s_ccs811_iic_readbuff(S_CCS811_ALG_RESULT_DATA, \
// //                                      data, S_CCS811_ALG_RESULT_DATA_LEN);
// //
// //    if(rslt)
// //    {
// //        S_CCS811_DEBUG("Get new data failed\r\n");
// //        return (-1);
// //    }
// //    else
// //    {
// //
// //        if(0)//data[4] > S_CCS811_STATUS_MEASTHRE)
// //        {
// //            S_CCS811_DEBUG("Status may error, 0x%02x\r\n", data[4]);
// //            return (-2);
// //        }
// //        else
// //        {
// //            ccs811_t->eCO2 = (unsigned short)(data[0] << 8) | (unsigned short)data[1];
// //            ccs811_t->TVOC = (unsigned short)(data[2] << 8) | (unsigned short)data[3];
// //        }
// //    }
// //    return 0;

// //static signed char s_ccs811_datareadycheck(void)
// //{
// //    unsigned char status;
// //    status = s_ccs811_readstatus();
// //    if(S_CCS811_STATUS_DATA_READY & status)
// //    {
// //        return 0;
// //    }
// //    else
// //    {
// //        return (-1);
// //    }
// }


void S_CCS811_HardwareReset(void)
{
    s_ccs811_nReset_enable();
    s_ccs811_delay_ms(20);
    s_ccs811_nReset_disable();
}

signed char S_CCS811_SoftwareReset(void)
{
    signed char rslt = 0U;
    rslt = s_ccs811_iic_writebuff(S_CCS811_SW_RESET, s_ccs811_swreset_data, \
                               sizeof(s_ccs811_swreset_data) / sizeof(unsigned char));

    s_ccs811_delay_ms(1);
    return rslt;
}

signed char S_CCS811_PinInit(void)
{
//    signed char rslt = 0U;

    if(0 != s_ccs811_gpio_outputinit())
    {
        S_CCS811_DEBUG("GPIO output failed\r\n");
        return (-1);
    }

    S_CCS811_HardwareReset();

    s_ccs811_nWake_enable();
    s_ccs811_delay_ms(2);

    return 0;
}

signed char S_CCS811_Init(s_ccs811_data_t * ccs811_t)
{
	
	unsigned char hw_id = 0U;
	unsigned char status = 0U;
	




	//HW ID check
	if(0 != s_ccs811_iic_readbuff(S_CCS811_HW_ID_REG, \
						&hw_id, 1))
	{
		S_CCS811_DEBUG("Get hardware data failed\r\n");
		return (-2);
	}
	
	if(S_CCS811_HW_ID_VALUE != hw_id)
	{
		S_CCS811_DEBUG("Hardware check failed\r\n");
		return (-3);
	}
	
	status = s_ccs811_readstatus();
	if(S_CCS811_STATUS_APP_VALID & status)
	{
		S_CCS811_DEBUG("Valid firmware loaded\r\n");
	}
	else
	{
		S_CCS811_DEBUG("No application firmware loaded\r\n");
		return (-4);
	}
	
	S_CCS811_SoftwareReset();


	//Firmware start
	if(s_ccs811_firmware_start())
	{
		S_CCS811_DEBUG("Firmware start command failed\r\n");
		return (-5);
	}

	s_ccs811_delay_ms(1);

	status = s_ccs811_readstatus();
	if(S_CCS811_STATUS_FM_MODE & status)
	{
		S_CCS811_DEBUG("Firmware in application mode\r\n");
	}
	else
	{
		S_CCS811_DEBUG("Firmware still in boot mode, state : 0x%02x\r\n", status);
		return (-6);
	}
	
	if(s_ccs811_meas_mode_set())
	{
		S_CCS811_DEBUG("Set meassure mode failed\r\n");
		return (-7);
	}
	
	s_ccs811_delay_ms(2);


	if(s_ccs811_meas_mode_check())
	{
	    return (-8);
	}

	ccs811_t->TVOC = 0U;
	ccs811_t->eCO2 = 0U;
	// ccs811_t->humi = 0U;
	ccs811_t->status = 0U;
	// ccs811_t->temp = 0U;

	return 0;
}

static void s_ccs811_eCO2_TVOC_rangeHandle(s_ccs811_data_t *ccs811_t)
{

    if(ccs811_t->TVOC > S_CCS811_TVOC_MAX)
    {
        ccs811_t->TVOC = 0;
    }

    if(ccs811_t->eCO2 < S_CCS811_eCO2_MIN)
    {
        ccs811_t->eCO2 = S_CCS811_eCO2_MIN;
    }
    else if(ccs811_t->eCO2 > S_CCS811_eCO2_MAX)
    {
        ccs811_t->eCO2 = S_CCS811_eCO2_MAX;
    }
}

// #define S_CCS811_SensorData_Len     10
signed char s_ccs811_getAlgResultData(s_ccs811_data_t *ccs811_t)
{
    signed char rslt = 0;
    unsigned char status = 0U;
    unsigned char meassure_mode = 0U;
    unsigned char algdata[S_CCS811_ALG_RESULT_DATA_LEN];

    // status = s_ccs811_readstatus();
    rslt = s_ccs811_iic_readbuff(S_CCS811_STATUS, &status, 1);
    rslt += s_ccs811_iic_readbuff(S_CCS811_MEAS_MODE, &meassure_mode, 1);
    rslt += s_ccs811_iic_readbuff(S_CCS811_ALG_RESULT_DATA, algdata, S_CCS811_ALG_RESULT_DATA_LEN);


    if(rslt)
    {
        S_CCS811_DEBUG("Read AlgResult Data error\r\n");
        return (-1);
    }
    else
    {
        // status = algdata[0];
        
        if(status & S_CCS811_STATUS_ERROR)
        {
            S_CCS811_DEBUG("Sensor status error.\r\n");
            S_CCS811_Test();
        }
        else if(status & S_CCS811_STATUS_DATA_READY)
        {
            //The status in algdata register must equal status register
            ccs811_t->status = algdata[0 + 4];
            ccs811_t->errorID = algdata[0 + 5];
            if(status != ccs811_t->status)
            {
                S_CCS811_DEBUG("Status error S :0x%02x/AlS :0x%02x, E :0x%02x\r\n");
            }
            else
            {
                // H_CC2640R2F_UART_Debugprinthex(algdata, 10);
                ccs811_t->eCO2 = (unsigned short)(algdata[0] << 8) | \
                                       (unsigned short)algdata[0 + 1];
                ccs811_t->TVOC = (unsigned short)(algdata[0 + 2] << 8) | \
                                       (unsigned short)algdata[0 + 3];

                s_ccs811_eCO2_TVOC_rangeHandle(ccs811_t);

                S_CCS811_DEBUG("OK :eco2 :%d ppm\tvoc :%d ppb\r\n", ccs811_t->eCO2, ccs811_t->TVOC);

                sprintf(s_ccs811_out_data, "OK :eco2 :%d ppm\tvoc :%d ppb\r\n\0", ccs811_t->eCO2, ccs811_t->TVOC);
                s_ccs811_out_data_len = strlen(s_ccs811_out_data);
            }
        }
        else
        {
            S_CCS811_DEBUG("Data not ready or other error S :0x%02x\r\n", status);
        }
        
    }
    return 0;
}

signed char s_ccs811_setEnvironmentData(s_ccs811_data_t *ccs811_t)
{
//    signed char rslt = 0;
    // unsigned char status;
    // unsigned char envdata[S_CCS811_ENV_DATA_LEN];

    // rslt = s_ccs811_iic_readbuff(S_CCS811_STATUS, &status, 1);
    // rslt += s_ccs811_iic_readbuff(S_CCS811_ENV_DATA, envdata, S_CCS811_ENV_DATA_LEN);

    // if(rslt)
    // {
    //     S_CCS811_DEBUG("Read Environment Data error\r\n");
    //     return (-1);
    // }
    // else
    // {
    //     if(status & S_CCS811_STATUS_ERROR)
    //     {
    //         S_CCS811_DEBUG("Sensor status error.\r\n");
    //         S_CCS811_Test();
    //     }
    //     else
    //     {
    //         ccs811_t->humi = 
    //     }
    // }

    return 0;
}

void S_CCS811_Test(void)
{
    while(1)
    {
        if(S_CCS811_Init(&ccs811_t))
        {
            s_ccs811_delay_ms(1000);
            //while(1);
            continue;
        }
        else
        {
		break;
        }
    }


//    while(1)
//    {
//        s_ccs811_getnewdata(&ccs811_t);
//        s_ccs811_delay_ms(1500);
//    }


////	unsigned short addr = 0U;
////	signed char rslt = 0;
////	unsigned char data[5];
////
////	for(; addr < 256; addr++)
////	{
////		if((rslt = H_CC2640R2F_IICS_ReadBuff(addr, 0x00, data, 1)))
////		{
//////			S_CCS811_DEBUG("%d, ", rslt);
////		    S_CCS811_DEBUG(".");
////		}
////		else
////		{
////			S_CCS811_DEBUG("The data is 0x%02x at 0x%02x\r\n", data[0], addr);
////		}
////	}
}
